// src/main/java/com/nb/service/impl/DeptServiceImpl.java
package com.nb.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.mybatisflex.core.paginate.Page;
import com.nb.dto.DeptCreateDTO;
import com.nb.dto.DeptStructureUpdateDTO;
import com.nb.dto.DeptUpdateDTO;
import com.nb.dto.DeptUserQueryDTO;
import com.nb.entity.Dept;
import com.nb.entity.User;
import com.nb.mapper.DeptMapper;
import com.nb.mapper.UserMapper;
import com.nb.service.DeptService;
import com.nb.service.UserService;
import com.nb.vo.DeptDetailVO;
import com.nb.vo.DeptTreeVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.mybatisflex.core.query.QueryWrapper;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DeptServiceImpl implements DeptService {

    @Autowired
    private DeptMapper deptMapper;

    @Autowired  // 添加UserService依赖注入
    private UserService userService;

    @Autowired  // 新增：注入UserMapper
    private UserMapper userMapper;

    @Override
    @Transactional
    public Long createDept(DeptCreateDTO deptCreateDTO) {
        // 校验部门名称唯一性
        if (!checkDeptNameUnique(deptCreateDTO.getName(), deptCreateDTO.getParentId())) {
            log.warn("Dept name is not unique: {} under parent {}",
                    deptCreateDTO.getName(), deptCreateDTO.getParentId());
            throw new RuntimeException("同一父部门下不能有相同名称的子部门");
        }

        // 构建部门实体
        Dept dept = new Dept();
        BeanUtils.copyProperties(deptCreateDTO, dept);
        dept.setIsDelete(0);
        dept.setCreatedBy("system");
        dept.setCreatedTime(java.time.LocalDateTime.now());
        dept.setUpdatedTime(java.time.LocalDateTime.now());

        // 先保存部门获取ID
        deptMapper.insert(dept);
        Long deptId = dept.getId();

        // 生成层级路径
        String level = generateDeptLevel(deptCreateDTO.getParentId(), deptId);
        dept.setLevel(level);

        // 更新层级路径
        deptMapper.update(dept);

        log.info("Created new dept: {} with id: {}", deptCreateDTO.getName(), deptId);
        return deptId;
    }

    /**
     * 校验部门名称在同一父部门下是否唯一
     */
    private boolean checkDeptNameUnique(String name, Long parentId) {
        QueryWrapper queryWrapper = QueryWrapper.create()
                .where("name = ?", name)
                .and("parent_id = ?", parentId)
                .and("is_delete = 0");

        return deptMapper.selectOneByQuery(queryWrapper) == null;
    }

    /**
     * 生成部门层级路径
     */
    private String generateDeptLevel(Long parentId, Long currentId) {
        if (parentId == null) {
            // 根部门，层级为自身ID
            return String.valueOf(currentId);
        }

        // 查询父部门信息
        Dept parentDept = deptMapper.selectOneById(parentId);
        if (parentDept == null) {
            throw new RuntimeException("父部门不存在");
        }

        // 父部门层级 + "." + 当前部门ID
        return parentDept.getLevel() + "." + currentId;
    }

    @Transactional
    @Override
    public boolean updateDept(DeptUpdateDTO deptUpdateDTO) {
        // 1. 校验部门是否存在
        Dept existDept = deptMapper.selectOneById(deptUpdateDTO.getId());
        if (existDept == null || existDept.getIsDelete() == 1) {
            log.warn("Dept not found or deleted: {}", deptUpdateDTO.getId());
            throw new RuntimeException("部门不存在或已被删除");
        }

        // 2. 校验父部门是否存在（如果父部门ID有值）
        if (deptUpdateDTO.getParentId() != null) {
            Dept parentDept = deptMapper.selectOneById(deptUpdateDTO.getParentId());
            if (parentDept == null || parentDept.getIsDelete() == 1) {
                log.warn("Parent dept not found or deleted: {}", deptUpdateDTO.getParentId());
                throw new RuntimeException("父部门不存在或已被删除");
            }

            // 3. 不能将自己设置为父部门
            if (deptUpdateDTO.getId().equals(deptUpdateDTO.getParentId())) {
                throw new RuntimeException("不能将部门设置为自身的父部门");
            }

            // 4. 检查是否存在循环引用（父部门不能是当前部门的子部门）
            if (isChildOf(deptUpdateDTO.getParentId(), deptUpdateDTO.getId())) {
                throw new RuntimeException("不能将子部门设置为父部门，会导致循环引用");
            }
        }

        // 5. 校验部门名称唯一性（排除自身）
        if (!checkDeptNameUniqueForUpdate(deptUpdateDTO)) {
            log.warn("Dept name is not unique: {} under parent {}",
                    deptUpdateDTO.getName(), deptUpdateDTO.getParentId());
            throw new RuntimeException("同一父部门下不能有相同名称的子部门");
        }

        // 6. 记录原始层级（用于后续更新子部门）
        String oldLevel = existDept.getLevel();

        // 7. 更新部门基本信息
        BeanUtils.copyProperties(deptUpdateDTO, existDept);
        existDept.setUpdatedBy(StpUtil.getLoginIdAsString()); // 当前登录用户
        existDept.setUpdatedTime(LocalDateTime.now());

        // 8. 如果父部门有变化，重新生成层级路径
        if (!equals(existDept.getParentId(), deptUpdateDTO.getParentId())) {
            String newLevel = generateDeptLevel(deptUpdateDTO.getParentId(), existDept.getId());
            existDept.setLevel(newLevel);

            // 9. 更新所有子部门的层级路径
            updateChildDeptLevels(oldLevel, newLevel);
        }

        // 10. 执行更新
        int rows = deptMapper.update(existDept);
        log.info("Updated dept: {} with id: {}", deptUpdateDTO.getName(), deptUpdateDTO.getId());
        return rows > 0;
    }

    /**
     * 校验部门名称唯一性（更新时排除自身）
     */
    private boolean checkDeptNameUniqueForUpdate(DeptUpdateDTO dto) {
        QueryWrapper queryWrapper = QueryWrapper.create()
                .where("name = ?", dto.getName())
                .and("parent_id = ?", dto.getParentId())
                .and("is_delete = 0")
                .and("id <> ?", dto.getId()); // 排除自身

        return deptMapper.selectOneByQuery(queryWrapper) == null;
    }

    /**
     * 检查目标部门是否是当前部门的子部门（用于防止循环引用）
     */
    private boolean isChildOf(Long targetDeptId, Long currentDeptId) {
        QueryWrapper queryWrapper = QueryWrapper.create()
                .where("id = ?", targetDeptId)
                .and("level LIKE ?", "%." + currentDeptId + ".%") // 包含当前部门ID在层级中
                .or("level = ?", currentDeptId) // 或者直接是当前部门
                .and("is_delete = 0");

        return deptMapper.selectOneByQuery(queryWrapper) != null;
    }

    /**
     * 更新所有子部门的层级路径
     * @param oldParentLevel 旧的父层级路径
     * @param newParentLevel 新的父层级路径
     */
    private void updateChildDeptLevels(String oldParentLevel, String newParentLevel) {
        // 查询所有以旧层级为前缀的子部门
        QueryWrapper queryWrapper = QueryWrapper.create()
                .where("level LIKE ?", oldParentLevel + ".%")
                .and("is_delete = 0");

        List<Dept> childDepts = deptMapper.selectListByQuery(queryWrapper);

        // 批量更新子部门层级
        for (Dept child : childDepts) {
            String newLevel = child.getLevel().replaceFirst(oldParentLevel, newParentLevel);
            child.setLevel(newLevel);
            child.setUpdatedTime(LocalDateTime.now());
            child.setUpdatedBy(StpUtil.getLoginIdAsString());
            deptMapper.update(child);
        }
        log.info("Updated {} child depts' levels from {} to {}", childDepts.size(), oldParentLevel, newParentLevel);
    }

    // 已有的其他方法（checkDeptNameUnique、generateDeptLevel等）...

    private boolean equals(Object a, Object b) {
        return (a == b) || (a != null && a.equals(b));
    }
    @Override
    @Transactional
    public int deleteDept(Long id) {
        // 1. 检查部门是否存在且未被删除
        Dept dept = deptMapper.selectOneById(id);
        if (dept == null || dept.getIsDelete() == 1) {
            log.warn("Dept not found or already deleted: {}", id);
            return 0;
        }

        // 2. 检查是否存在子部门（禁止删除有子部门的部门）
        QueryWrapper childQuery = QueryWrapper.create()
                .where("parent_id = ?", id)
                .and("is_delete = 0");
        List<Dept> childDepts = deptMapper.selectListByQuery(childQuery);
        if (!childDepts.isEmpty()) {
            log.warn("Cannot delete dept with child depts: {}", id);
            throw new RuntimeException("存在子部门，无法删除");
        }

        // 3. 检查部门下是否有用户（根据业务需求决定是否允许删除）
        QueryWrapper userQuery = QueryWrapper.create()
                .where("dept_id = ?", id)
                .and("is_delete = 0");
        // 修正：使用带条件的查询，而非查询所有用户
        List<User> users = userMapper.selectListByQuery(userQuery);
        if (!users.isEmpty()) {
            log.warn("Cannot delete dept with associated users: {}", id);
            throw new RuntimeException("部门下存在用户，无法删除");
        }

        // 4. 执行逻辑删除（更新is_delete为1）
        Dept deptToDelete = new Dept();
        deptToDelete.setId(id);
        deptToDelete.setIsDelete(1); // 标记为删除
        deptToDelete.setUpdatedBy(StpUtil.getLoginIdAsString()); // 当前登录用户
        deptToDelete.setUpdatedTime(LocalDateTime.now());

        int rows = deptMapper.update(deptToDelete);
        log.info("Deleted dept: {} result: {}", id, rows > 0);
        return rows;
    }
    @Override
    public Page<Dept> getDeptPage(Integer pageNum, Integer pageSize, String name, Long parentId) {
        // 1. 构建查询条件（只查询未删除的部门）
        QueryWrapper queryWrapper = QueryWrapper.create()
                .eq(Dept::getIsDelete, 0); // 逻辑删除标记：0-未删除

        // 2. 部门名称模糊查询
        if (name != null && !name.trim().isEmpty()) {
            queryWrapper.like(Dept::getName, name.trim());
        }

        // 3. 父部门ID精确查询
        if (parentId != null) {
            queryWrapper.eq(Dept::getParentId, parentId);
        }

        // 4. 排序规则：按sort升序（小的在前），再按id升序（创建早的在前）
        queryWrapper.orderBy(Dept::getSort, true)
                .orderBy(Dept::getId, true);

        // 5. 执行分页查询（基于MyBatis-Flex原生分页）
        Page<Dept> page = new Page<>(pageNum, pageSize);
        Page<Dept> deptPage = deptMapper.paginate(page, queryWrapper);

        log.info("Dept page query completed: total={}, pages={}",
                deptPage.getTotalRow(), deptPage.getTotalPage());

        return deptPage;
    }

    @Override
    public DeptDetailVO getDeptDetail(Long id) {
        // 1. 查询当前部门（仅查询未删除的）
        QueryWrapper queryWrapper = QueryWrapper.create()
                .eq(Dept::getId, id)
                .eq(Dept::getIsDelete, 0); // 逻辑删除标记：0-未删除

        Dept dept = deptMapper.selectOneByQuery(queryWrapper);
        if (dept == null) {
            return null;
        }

        // 2. 转换为VO
        DeptDetailVO deptVO = DeptDetailVO.fromDept(dept);

        // 3. 查询父部门信息（如果存在）
        Long parentId = dept.getParentId();
        if (parentId != null) {
            QueryWrapper parentQuery = QueryWrapper.create()
                    .eq(Dept::getId, parentId)
                    .eq(Dept::getIsDelete, 0);
            Dept parentDept = deptMapper.selectOneByQuery(parentQuery);
            deptVO.setParentDept(parentDept);
        }

        log.info("Dept detail query completed: id={}, name={}", id, dept.getName());
        return deptVO;
    }

    @Override
    public List<User> getUsersByDeptId(Long deptId) {
        // 校验部门ID合法性
        if (deptId == null || deptId <= 0) {
            log.warn("查询用户的部门ID非法: {}", deptId);
            return Collections.emptyList();
        }

        // 构建查询条件：部门ID匹配 + 未删除
        QueryWrapper queryWrapper = QueryWrapper.create()
                .eq("dept_id", deptId)
                .eq("is_delete", 0);

        // 执行查询
        List<User> users = userMapper.selectListByQuery(queryWrapper);
        log.info("查询部门[{}]下的用户，共{}条记录", deptId, users.size());
        return users;
    }
    @Override
    public List<DeptTreeVO> getDeptTree() {
        // 1. 查询所有未删除的部门
        QueryWrapper queryWrapper = QueryWrapper.create()
                .eq("is_delete", 0)
                .orderBy("sort", true); // 按排序字段升序
        List<Dept> deptList = deptMapper.selectListByQuery(queryWrapper);

        // 2. 转换为VO列表
        List<DeptTreeVO> deptVOList = deptList.stream()
                .map(DeptTreeVO::fromDept)
                .collect(Collectors.toList());

        // 3. 构建部门树
        return buildDeptTree(deptVOList);
    }

    /**
     * 构建部门树形结构
     */
    private List<DeptTreeVO> buildDeptTree(List<DeptTreeVO> deptVOList) {
        // 用Map存储部门ID与VO的映射，便于快速查找父部门
        Map<Long, DeptTreeVO> deptMap = new HashMap<>();
        for (DeptTreeVO deptVO : deptVOList) {
            deptMap.put(deptVO.getId(), deptVO);
        }

        List<DeptTreeVO> rootDepts = new ArrayList<>();

        for (DeptTreeVO deptVO : deptVOList) {
            Long parentId = deptVO.getParentId();
            if (parentId == null) {
                // 父ID为null的是根部门
                rootDepts.add(deptVO);
            } else {
                // 找到父部门并添加到子列表
                DeptTreeVO parentDept = deptMap.get(parentId);
                if (parentDept != null) {
                    parentDept.getChildren().add(deptVO);
                    // 对子部门按sort排序
                    parentDept.getChildren().sort(Comparator.comparingInt(DeptTreeVO::getSort));
                }
            }
        }

        // 对根部门按sort排序
        rootDepts.sort(Comparator.comparingInt(DeptTreeVO::getSort));
        return rootDepts;
    }

    @Override
    public Page<User> getDeptUsers(DeptUserQueryDTO queryDTO) {
        // 1. 校验部门是否存在
        Dept dept = deptMapper.selectOneById(queryDTO.getDeptId());
        if (dept == null || dept.getIsDelete() == 1) {
            log.warn("查询用户的部门不存在或已删除: {}", queryDTO.getDeptId());
            return new Page<>(); // 返回空分页
        }

        // 2. 构建查询条件：部门ID匹配 + 未删除用户
        QueryWrapper queryWrapper = QueryWrapper.create()
                .eq("dept_id", queryDTO.getDeptId())
                .eq("is_delete", 0)
                .orderBy("created_time", false); // 按创建时间倒序

        // 3. 执行分页查询
        Page<User> userPage = userMapper.paginate(
                new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize()),
                queryWrapper
        );

        log.info("查询部门[{}]下的用户，分页：{}，共{}条记录",
                queryDTO.getDeptId(), queryDTO.getPageNum(), userPage.getTotalRow());
        return userPage;
    }

    @Override
    @Transactional
    public boolean batchUpdateStructure(DeptStructureUpdateDTO updateDTO) {
        log.info("Received dept structure batch update request: {}", updateDTO);

        // 1. 校验所有部门是否存在且未被删除
        List<Long> deptIds = updateDTO.getDeptNodes().stream()
                .map(DeptStructureUpdateDTO.DeptNode::getId)
                .collect(Collectors.toList());

        QueryWrapper existQuery = QueryWrapper.create()
                .in("id", deptIds)  // 使用 in 方法正确绑定参数
                .and("is_delete = 0");
        List<Dept> existDepts = deptMapper.selectListByQuery(existQuery);
        Set<Long> existIds = existDepts.stream()
                .map(Dept::getId)
                .collect(Collectors.toSet());

        // 检查不存在的部门
        List<Long> notExistIds = deptIds.stream()
                .filter(id -> !existIds.contains(id))
                .collect(Collectors.toList());
        if (!notExistIds.isEmpty()) {
            log.warn("Depts not found or deleted: {}", notExistIds);
            throw new RuntimeException("部门不存在或已删除：" + notExistIds);
        }

        // 2. 构建部门ID到节点的映射
        Map<Long, DeptStructureUpdateDTO.DeptNode> nodeMap = updateDTO.getDeptNodes().stream()
                .collect(Collectors.toMap(
                        DeptStructureUpdateDTO.DeptNode::getId,
                        node -> node
                ));

        // 3. 校验循环引用（父部门不能是子部门）
        for (DeptStructureUpdateDTO.DeptNode node : updateDTO.getDeptNodes()) {
            Long parentId = node.getParentId();
            if (parentId != null && deptIds.contains(parentId)) { // 父部门在本次调整范围内
                if (isChildOf(parentId, node.getId(), nodeMap, existDepts)) {
                    log.warn("Circular reference detected: dept {} parent is {}", node.getId(), parentId);
                    throw new RuntimeException("部门" + node.getId() + "与父部门" + parentId + "存在循环引用");
                }
            }
        }

        // 4. 按层级排序部门（先处理父部门，再处理子部门）
        List<Dept> sortedDepts = sortDeptsByLevel(existDepts);

        // 5. 批量更新部门的父ID和排序值
        for (Dept dept : sortedDepts) {
            DeptStructureUpdateDTO.DeptNode node = nodeMap.get(dept.getId());
            if (node == null) continue;

            // 记录旧层级（用于更新子部门）
            String oldLevel = dept.getLevel();

            // 更新父ID和排序
            dept.setParentId(node.getParentId());
            dept.setSort(node.getSort());
            dept.setUpdatedBy(StpUtil.getLoginIdAsString());
            dept.setUpdatedTime(LocalDateTime.now());

            // 重新生成层级路径
            String newLevel = generateDeptLevel(node.getParentId(), dept.getId());
            dept.setLevel(newLevel);

            // 执行更新
            deptMapper.update(dept);

            // 如果层级有变化，更新所有子部门的层级
            if (!Objects.equals(oldLevel, newLevel)) {
                updateChildDeptLevels(oldLevel, newLevel);
            }
        }

        // 6. 校验同一父部门下的名称唯一性（批量调整后可能出现冲突）
        validateDeptNameUniquenessAfterUpdate(updateDTO, existDepts);

        log.info("Successfully updated dept structure for {} depts", updateDTO.getDeptNodes().size());
        return true;
    }

    /**
     * 按层级排序部门（确保父部门在子部门之前处理）
     */
    private List<Dept> sortDeptsByLevel(List<Dept> depts) {
        return depts.stream()
                .sorted(Comparator.comparingInt(dept -> dept.getLevel().split("\\.").length))
                .collect(Collectors.toList());
    }

    /**
     * 检查是否存在循环引用（递归）
     */
    private boolean isChildOf(Long targetDeptId, Long currentDeptId,
                              Map<Long, DeptStructureUpdateDTO.DeptNode> nodeMap,
                              List<Dept> existDepts) {
        // 目标部门不在调整列表中时，使用数据库中的原始父ID判断
        DeptStructureUpdateDTO.DeptNode targetNode = nodeMap.get(targetDeptId);
        Long targetParentId = targetNode != null ? targetNode.getParentId() :
                existDepts.stream()
                        .filter(d -> d.getId().equals(targetDeptId))
                        .findFirst()
                        .map(Dept::getParentId)
                        .orElse(null);

        if (targetParentId == null) {
            return false; // 目标部门是根部门，不可能是子部门
        }
        if (targetParentId.equals(currentDeptId)) {
            return true; // 直接子部门
        }
        return isChildOf(targetParentId, currentDeptId, nodeMap, existDepts); // 递归检查
    }

    /**
     * 批量调整后校验同一父部门下的名称唯一性
     */
    private void validateDeptNameUniquenessAfterUpdate(DeptStructureUpdateDTO updateDTO, List<Dept> existDepts) {
        // 构建父ID到部门列表的映射
        Map<Long, List<Dept>> parentDeptMap = new HashMap<>();
        for (Dept dept : existDepts) {
            Long parentId = updateDTO.getDeptNodes().stream()
                    .filter(node -> node.getId().equals(dept.getId()))
                    .findFirst()
                    .map(DeptStructureUpdateDTO.DeptNode::getParentId)
                    .orElse(dept.getParentId());

            parentDeptMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(dept);
        }

        // 检查每个父部门下的名称唯一性
        for (Map.Entry<Long, List<Dept>> entry : parentDeptMap.entrySet()) {
            Long parentId = entry.getKey();
            List<Dept> depts = entry.getValue();

            Set<String> nameSet = new HashSet<>();
            for (Dept dept : depts) {
                if (nameSet.contains(dept.getName())) {
                    throw new RuntimeException("父部门" + parentId + "下存在重复名称的部门：" + dept.getName());
                }
                nameSet.add(dept.getName());
            }
        }
    }
}